<template>
    <view v-if="show" class="u-tabbar" @touchmove.stop.prevent="() => {}">
        <view class="u-tabbar__content safe-area-inset-bottom" :style="{
            height: $u.addUnit(height),
            backgroundColor: bgColor,
        }" :class="{
            'u-border-top': borderTop
        }">
            <view class="u-tabbar__content__item" v-for="(item, index) in list" :key="index" :class="{
                'u-tabbar__content__circle': midButton &&item.midButton
            }" @tap.stop="clickHandler(index)" :style="{
                backgroundColor: bgColor
            }">
                <view :class="[
                    midButton && item.midButton ? 'u-tabbar__content__circle__button' : 'u-tabbar__content__item__button'
                ]">
                    <u-icon
                        :size="midButton && item.midButton ? midButtonSize : iconSize"
                        :name="elIconPath(index)"
                        img-mode="scaleToFill"
                        :color="elColor(index)"
                        :custom-prefix="item.customIcon ? 'custom-icon' : 'uicon'"
                    ></u-icon>
                    <u-badge :count="item.count" :is-dot="item.isDot"
                        v-if="item.count"
                        :offset="[-2, getOffsetRight(item.count, item.isDot)]"
                    ></u-badge>
                </view>
                <view class="u-tabbar__content__item__text" :style="{
                    color: elColor(index)
                }">
                    <text class="u-line-1">{{item.text}}</text>
                </view>
            </view>
            <view v-if="midButton" class="u-tabbar__content__circle__border" :class="{
                'u-border': borderTop,
            }" :style="{
                backgroundColor: bgColor,
                left: midButtonLeft
            }">
            </view>
        </view>
        <!-- 这里加上一个48rpx的高度,是为了增高有凸起按钮时的防塌陷高度(也即按钮凸出来部分的高度) -->
        <view class="u-fixed-placeholder safe-area-inset-bottom" :style="{
                height: `calc(${$u.addUnit(height)} + ${midButton ? 48 : 0}rpx)`,
            }"></view>
    </view>
</template>

<script>
    export default {
        props: {
            // 显示与否
            show: {
                type: Boolean,
                default: true
            },
            // 通过v-model绑定current值
            value: {
                type: [String, Number],
                default: 0
            },
            // 整个tabbar的背景颜色
            bgColor: {
                type: String,
                default: '#ffffff'
            },
            // tabbar的高度，默认50px，单位任意，如果为数值，则为rpx单位
            height: {
                type: [String, Number],
                default: '50px'
            },
            // 非凸起图标的大小，单位任意，数值默认rpx
            iconSize: {
                type: [String, Number],
                default: 40
            },
            // 凸起的图标的大小，单位任意，数值默认rpx
            midButtonSize: {
                type: [String, Number],
                default: 90
            },
            // 激活时的演示，包括字体图标，提示文字等的演示
            activeColor: {
                type: String,
                default: '#303133'
            },
            // 未激活时的颜色
            inactiveColor: {
                type: String,
                default: '#606266'
            },
            // 是否显示中部的凸起按钮
            midButton: {
                type: Boolean,
                default: false
            },
            // 配置参数
            list: {
                type: Array,
                default () {
                    return []
                }
            },
            // 切换前的回调
            beforeSwitch: {
                type: Function,
                default: null
            },
            // 是否显示顶部的横线
            borderTop: {
                type: Boolean,
                default: true
            },
            // 是否隐藏原生tabbar
            hideTabBar: {
                type: Boolean,
                default: true
            },
        },
        data() {
            return {
                // 由于安卓太菜了，通过css居中凸起按钮的外层元素有误差，故通过js计算将其居中
                midButtonLeft: '50%',
                pageUrl: '', // 当前页面URL
            }
        },
        created() {
            // 是否隐藏原生tabbar
            if(this.hideTabBar) uni.hideTabBar();
            // 获取引入了u-tabbar页面的路由地址，该地址没有路径前面的"/"
            let pages = getCurrentPages();
            // 页面栈中的最后一个即为项为当前页面，route属性为页面路径
            this.pageUrl = pages[pages.length - 1].route;
        },
        computed: {
            elIconPath() {
                return (index) => {
                    // 历遍u-tabbar的每一项item时，判断是否传入了pagePath参数，如果传入了
                    // 和data中的pageUrl参数对比，如果相等，即可判断当前的item对应当前的tabbar页面，设置高亮图标
                    // 采用这个方法，可以无需使用v-model绑定的value值
                    let pagePath = this.list[index].pagePath;
                    // 如果定义了pagePath属性，意味着使用系统自带tabbar方案，否则使用一个页面用几个组件模拟tabbar页面的方案
                    // 这两个方案对处理tabbar item的激活与否方式不一样
                    if(pagePath) {
                        if(pagePath == this.pageUrl || pagePath == '/' + this.pageUrl) {
                            return this.list[index].selectedIconPath;
                        } else {
                            return this.list[index].iconPath;
                        }
                    } else {
                        // 普通方案中，索引等于v-model值时，即为激活项
                        return index == this.value ? this.list[index].selectedIconPath : this.list[index].iconPath
                    }
                }
            },
            elColor() {
                return (index) => {
                    // 判断方法同理于elIconPath
                    let pagePath = this.list[index].pagePath;
                    if(pagePath) {
                        if(pagePath == this.pageUrl || pagePath == '/' + this.pageUrl) return this.activeColor;
                        else return this.inactiveColor;
                    } else {
                        return index == this.value ? this.activeColor : this.inactiveColor;
                    }
                }
            }
        },
        mounted() {
            this.midButton && this.getMidButtonLeft();
        },
        methods: {
            async clickHandler(index) {
                if(this.beforeSwitch && typeof(this.beforeSwitch) === 'function') {
                    // 执行回调，同时传入索引当作参数
                    // 在微信，支付宝等环境(H5正常)，会导致父组件定义的customBack()函数体中的this变成子组件的this
                    // 通过bind()方法，绑定父组件的this，让this.customBack()的this为父组件的上下文
                    let beforeSwitch = this.beforeSwitch.bind(this.$u.$parent.call(this))(index);
                    // 判断是否返回了promise
                    if (!!beforeSwitch && typeof beforeSwitch.then === 'function') {
                        await beforeSwitch.then(res => {
                            // promise返回成功，
                            this.switchTab(index);
                        }).catch(err => {

                        })
                    } else if(beforeSwitch === true) {
                        // 如果返回true
                        this.switchTab(index);
                    }
                } else {
                    this.switchTab(index);
                }
            },
            // 切换tab
            switchTab(index) {
                // 发出事件和修改v-model绑定的值
                this.$emit('change', index);
                // 如果有配置pagePath属性，使用uni.switchTab进行跳转
                if(this.list[index].pagePath) {
                    uni.switchTab({
                        url: this.list[index].pagePath
                    })
                } else {
                    // 如果配置了papgePath属性，将不会双向绑定v-model传入的value值
                    // 因为这个模式下，不再需要v-model绑定的value值了，而是通过getCurrentPages()适配
                    this.$emit('input', index);
                }
            },
            // 计算角标的right值
            getOffsetRight(count, isDot) {
                // 点类型，count大于9(两位数)，分别设置不同的right值，避免位置太挤
                if(isDot) {
                    return -20;
                } else if(count > 9) {
                    return -40;
                } else {
                    return -30;
                }
            },
            // 获取凸起按钮外层元素的left值，让其水平居中
            getMidButtonLeft() {
                let windowWidth = this.$u.sys().windowWidth;
                // 由于安卓中css计算left: 50%的结果不准确，故用js计算
                this.midButtonLeft = (windowWidth / 2) + 'px';
            }
        }
    }
</script>

<style scoped lang="scss">
    @import "../../libs/css/style.components.scss";
    .u-fixed-placeholder {
        /* #ifndef APP-NVUE */
        box-sizing: content-box;
        /* #endif */
    }

    .u-tabbar {

        &__content {
            @include vue-flex;
            align-items: center;
            position: relative;
            position: fixed;
            bottom: 0;
            left: 0;
            width: 100%;
            z-index: 998;
            /* #ifndef APP-NVUE */
            box-sizing: content-box;
            /* #endif */

            &__circle__border {
                border-radius: 100%;
                width: 110rpx;
                height: 110rpx;
                top: -48rpx;
                position: absolute;
                z-index: 4;
                background-color: #ffffff;
                // 由于安卓的无能，导致只有3个tabbar item时，此css计算方式有误差
                // 故使用js计算的形式来定位，此处不注释，是因为js计算有延后，避免出现位置闪动
                left: 50%;
                transform: translateX(-50%);

                &:after {
                    border-radius: 100px;
                }
            }

            &__item {
                flex: 1;
                justify-content: center;
                height: 100%;
                padding: 12rpx 0;
                @include vue-flex;
                flex-direction: column;
                align-items: center;
                position: relative;

                &__button {
                    position: absolute;
                    top: 14rpx;
                    left: 50%;
                    transform: translateX(-50%);
                }

                &__text {
                    color: $u-content-color;
                    font-size: 26rpx;
                    line-height: 28rpx;
                    position: absolute;
                    bottom: 14rpx;
                    left: 50%;
                    transform: translateX(-50%);
                    width: 100%;
                    text-align: center;
                }
            }

            &__circle {
                position: relative;
                @include vue-flex;
                flex-direction: column;
                justify-content: space-between;
                z-index: 10;
                /* #ifndef APP-NVUE */
                height: calc(100% - 1px);
                /* #endif */

                &__button {
                    width: 90rpx;
                    height: 90rpx;
                    border-radius: 100%;
                    @include vue-flex;
                    justify-content: center;
                    align-items: center;
                    position: absolute;
                    background-color: #ffffff;
                    top: -40rpx;
                    left: 50%;
                    z-index: 6;
                    transform: translateX(-50%);
                }
            }
        }
    }
</style>
